home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / gfx / show / MerlinGfx.lha / MerlinFLI.c < prev    next >
C/C++ Source or Header  |  1995-06-07  |  49KB  |  1,644 lines

  1.  
  2. /*    MerlinFLI - Play .FLI/.FLC animations with Merlin
  3.  
  4.         Rainer Trunz, Januar 1995
  5.  
  6.     This program plays .FLI (fixed to 320x200) or .FLC (any
  7.     resolution) anim files in a PIP-window on a Merlin graphic board
  8.     that is capable of producing an 8 bit, CLUT-based chunky pixel
  9.     display.
  10.  
  11.     History:
  12.     V1.1 21.01.1995  First version, already stable, 'Quick' and
  13.                      dirty hack, that is, it was meant as a 'simple'
  14.                      test for programming within a 2.6.1/2.3.3 - gcc
  15.                      baserel-environment (and the Merlin board, too).
  16.  
  17.     V1.2 26.01.1995  Second version, made read.c really bug-free,
  18.                      changed Open to AllocDosObject for SetVBuf,
  19.                      changed time delay to real thing     
  20.  
  21.     This code is mostly based on xflick for X11 systems. What follows is
  22.     the original comment:
  23.  
  24.     xflick - Ron Schnell, March, 1991
  25.  
  26.     This code is provided as is, with no warrantees, expressed
  27.     or implied.  I believe this code to be free of encumbrance,
  28.     and offer it to the public domain.  I ask, however, that
  29.     this paragraph and my name be retained in any modified
  30.     versions of the file you may make, and that you notify me
  31.     of any improvements you make to the code.
  32.  
  33.     Ron Schnell (ronnie@sos.com)
  34.  
  35.     The following changes are from Michael Pall
  36.     (pall@rz.uni-karlsruhe.de) Mar 25-28 1991:
  37.  
  38.     Lots of bugfixes and changes to the structure of the files.
  39.     The file is interpreted before we display it.
  40.     Moved the interpretation part to read.c.
  41.     We use Pixmaps and/or XImages.
  42.     Added interactive input to change the speed/single step.
  43.  
  44.     The following extensions are from Klaus Ehrenfried
  45.     (klaus@spock.es.go.dlr.de) Oct 23-24 1992:
  46.  
  47.     Add handling of FLI_DELTA and FLI_256_COLOR chunks.
  48.     Recognize magic number FLC_MAGIC = 0xaf12 for newer
  49.     flic files.
  50. */
  51.  
  52. #include "amiga.h"
  53. #include "eflick.h"
  54. #include "proto.h"
  55.  
  56. #include <stdlib.h>
  57.  
  58. #include <inline/strsup.h>
  59.  
  60. #include <sys/types.h>
  61. #include <sys/signal.h>
  62. #include <sys/time.h>
  63.  
  64. /* Define BOOLEAN, TRUE, and FALSE. */
  65.  
  66. #define BOOLEAN int
  67. #define TRUE      1
  68. #define FALSE     0
  69.  
  70. #define OUTPUT(s)      if (!quietFlag) FPrintf (stdout, s)
  71. #define OUTPUT1(s,a)   if (!quietFlag) FPrintf (stdout, s, a)
  72. #define OUTPUT2(s,a,b) if (!quietFlag) FPrintf (stdout, s, a, b)
  73.  
  74. #define SET_A_PEN(a)   OUTPUT1("\033[3%ldm", a)
  75.  
  76. /*============================================================================*
  77.  * IDCMP-Messages am Window-UserPort abfragen und entsprechende Maßnahmen     *
  78.  * ergreifen.                                                                 *
  79.  *============================================================================*/
  80.  
  81. #define CheckWindow(w) {                                                              \
  82.     if (w) {                                                                          \
  83.         while (imsg = (struct IntuiMessage *) GetMsg ((w)->UserPort) ) {              \
  84.             msg = *imsg;                                                              \
  85.             ReplyMsg ((struct Message *) imsg);                                       \
  86.             switch (msg.Class) {                                                      \
  87.                 case IDCMP_CLOSEWINDOW : Quit (NO_ERR);                               \
  88.                 case IDCMP_CHANGEWINDOW: hrMoveSecondView (hrh, (w)->LeftEdge + left, \
  89.                                                                 (w)->TopEdge  + top); \
  90.                                          Resize ();                            break; \
  91.                 case IDCMP_GADGETDOWN  : CurrentGadget = GADGETID(msg);        break; \
  92.                 case IDCMP_GADGETUP    : CheckGadget (CurrentGadget);                 \
  93.                                          CurrentGadget = NO_GADGET;            break; \
  94.                 case IDCMP_INTUITICKS  : CheckGadget (CurrentGadget);          break; \
  95.                 case IDCMP_RAWKEY      : CheckKey (msg.Code, msg.Qualifier);   break; \
  96.                 case IDCMP_MENUPICK    : CheckMenu (msg.Code); break;          break; \
  97.                 case IDCMP_ACTIVEWINDOW: hrSetPaletteRGBA (hrh, curctab, 0, 255); break; \
  98.                 case IDCMP_INACTIVEWINDOW: hrSetPaletteRGBA (hrh, coltab, 0, 255); break; \
  99.             }                                                                         \
  100.         }                                                                             \
  101.     }                                                                                 \
  102. }
  103.  
  104. /*============================================================================*
  105.  *  Oeffentliche Variablen / Strukturen.                                      *
  106.  *============================================================================*/
  107.  
  108. extern struct ExecBase *SysBase;
  109.  
  110. int quietFlag = FALSE;
  111.  
  112. char fileName[256];
  113.  
  114. unsigned char *map = NULL;    /* current image data */
  115.  
  116. struct IntuitionBase *IntuitionBase = NULL;
  117. struct GfxBase       *GfxBase       = NULL;
  118. struct Library       *GadToolsBase  = NULL;
  119. struct Library       *AslBase       = NULL;
  120. struct Library       *HRGSystemBase = NULL,
  121.                      *HRGRenderBase = NULL;
  122. struct HRHandle      *hrh = NULL;
  123.  
  124. BPTR fd = NULL;        /* The main file descriptor */
  125. BPTR stdout = NULL;    /* Standard Output  */
  126.  
  127. ULONG FrameSize = NULL;
  128.  
  129. int offx = 0, offy = 0,
  130.     offl = 0, offt = 0;
  131.  
  132. /*============================================================================*
  133.  *  Lokale Variablen / Strukturen.                                            *
  134.  *============================================================================*/
  135.  
  136. static struct Window        *FLI_win = NULL;
  137. static struct RastPort      *rp      = NULL;
  138. static struct IntuiMessage  *imsg    = NULL;
  139. static struct Screen        *Screen  = NULL;
  140. static struct Menu          *Menus   = NULL;
  141. static struct IntuiMessage  msg;
  142.  
  143. static struct HRBitMap      *hrbm    = NULL;
  144. static struct HRModePrefDat MyPrefs;
  145.  
  146. static APTR VisualInfo = NULL;
  147.  
  148. static UWORD CurrentGadget = NO_GADGET;
  149. static ULONG soerror = 0;
  150.  
  151. ULONG *coltab = NULL, *curctab = NULL;
  152.  
  153. static int InnerWidth = 0, InnerHeight = 0,
  154.            ScrollX = 0, ScrollY = 0,
  155.            Width = 0, Height = 0,
  156.            left, top;
  157.  
  158. static struct Gadget *LeftGadget  = NULL,
  159.                      *RightGadget = NULL,
  160.                      *UpGadget    = NULL,
  161.                      *DownGadget  = NULL,
  162.                      *HorizGadget = NULL,
  163.                      *VertGadget  = NULL;
  164.  
  165. static struct Image  *UpImage     = NULL,
  166.                      *DownImage   = NULL,
  167.                      *LeftImage   = NULL,
  168.                      *RightImage  = NULL;
  169.  
  170. static struct NewMenu NewMenu[] = {
  171.     NM_TITLE, (STRPTR)"Project",            NULL,       0, 0L, NULL,
  172.     NM_ITEM,  (STRPTR)"About...",          (STRPTR)"?", 0, 0L, NULL,
  173.     NM_ITEM,  (STRPTR)NM_BARLABEL,          NULL,       0, 0L, NULL,
  174.     NM_ITEM,  (STRPTR)"Quit",              (STRPTR)"Q", 0, 0L, NULL,
  175.     NM_TITLE, (STRPTR)"Window",             NULL      , 0, 0L, NULL,
  176.     NM_ITEM,  (STRPTR)"Reset To Defaults", (STRPTR)"R", 0, 0L, NULL,
  177.     NM_ITEM,  (STRPTR)"Save As Defaults",  (STRPTR)"S", 0, 0L, NULL,
  178.     NM_ITEM,  (STRPTR)"Last Saved",        (STRPTR)"L", 0, 0L, NULL,
  179.     NM_ITEM,  (STRPTR)NM_BARLABEL,          NULL,       0, 0L, NULL,
  180.     NM_ITEM,  (STRPTR)"Minimize",          (STRPTR)"-", 0, 0L, NULL,
  181.     NM_ITEM,  (STRPTR)"Maximize",          (STRPTR)"+", 0, 0L, NULL,
  182.     NM_END,   NULL, NULL, 0, 0L,   NULL };
  183.  
  184. static struct EasyStruct AboutRequest = {
  185.     sizeof(struct EasyStruct),
  186.     0,
  187.     "MerlinFLI/C",
  188.     "FLI/C Software Decoder\n"
  189.     "for the Merlin Graphics Accelerator\n\n"
  190.     "Version 1.2  ("__DATE__")\n\n"
  191.     "Copyright © 1995 Rainer Trunz",
  192.     "Continue"
  193. };
  194.  
  195. static char *version = "$VER: MerlinFLI 1.2 ("__DATE__")";
  196.  
  197. struct Device        *TimerBase    = NULL;
  198. struct timerequest    *TimerIO    = NULL;
  199. struct MsgPort        *TimerPort    = NULL;
  200. struct EClockVal    time0        = {NULL};
  201. struct EClockVal    time1        = {NULL};
  202.  
  203. ULONG totalframes;
  204. ULONG timerclosed = TRUE;
  205. double micros_per_eclock;    /* Length of EClock tick in microseconds */
  206.  
  207. int verbose = FALSE;
  208.  
  209. static flag_noint = FALSE;    /* Don't interpret file first */
  210.  
  211. static int fdelay = -1;        /* Frame delay */
  212. static int wwidth, wheight;    /* Width and height of the window */
  213. static int stepflag = 0;    /* Default: singlestep is off */
  214. static int onestep;            /* 1 if we should be loop waiting for a step */
  215.  
  216. /* The structure to hold the elements of the interpreted display list */
  217.  
  218. struct disp_list
  219. {
  220.     int disp_type;
  221.     int disp_frame;
  222.     UBYTE *disp_pix;
  223.     ULONG *disp_cols;
  224.     int disp_numcol;
  225.     int disp_begcol;
  226.     int disp_width, disp_height;
  227.     int disp_destx, disp_desty;
  228.     struct disp_list *disp_next;
  229. };
  230.  
  231. static struct disp_list disp_root;    /* The start of the display list */
  232. static struct disp_list *disp_cur;    /* The current position */
  233.  
  234. /* prototypes */
  235.  
  236. #ifndef LARGE
  237.  
  238. /*****************************************************************************
  239.  *
  240.  *  EasyReqArgs.asm    - EasyRequestArgs() für baserel Gnu-C ;-(((
  241.  *
  242.  *  ©`94 Rainer F. Trunz. Geschrieben für Gnu-C 2.3.3 !
  243.  *
  244.  *****************************************************************************/
  245.  
  246. ULONG EasyReqArgs (struct Window *window, struct EasyStruct *easyStruct,
  247.                          ULONG *idcmpPtr, ULONG args,...)
  248. {
  249.   __asm __volatile ("            | (ostring, format, {values})
  250.  
  251.     moveml    a2/a3/a6,sp@-
  252.  
  253.     lea        sp@(4*4),a3
  254.     moveml    a3@+,a0/a1/a2        | a3 is now ptr to tag-field
  255.     movel    a4@(_IntuitionBase:W),a6
  256.     jsr        a6@(-588)            | _LVOEasyRequestArgs
  257.  
  258.     moveml    sp@+,a2/a3/a6"
  259.  
  260.     : /* No Output */
  261.     : /* No Input */
  262.     : "d0","d1","a0","a1");
  263. }
  264.  
  265. /*****************************************************************************
  266.  *
  267.  *  SetGadAttrs.asm - SetGadgetAttrsA() für baserel Gnu-C ;-(((
  268.  *
  269.  *  ©`94 Rainer F. Trunz. Geschrieben für Gnu-C 2.3.3 !
  270.  *
  271.  *****************************************************************************/
  272.  
  273. ULONG SetGadAttrs (struct Gadget *gad, struct Window *win,
  274.                         struct Requester *req, ULONG args,...)
  275. {
  276.   __asm __volatile ("
  277.  
  278.     moveml    a2/a3/a6,sp@-
  279.  
  280.     lea        sp@(4*4),a3
  281.     moveml    a3@+,a0/a1/a2        | a3 is now ptr to tag-field
  282.     movel    a4@(_IntuitionBase:W),a6
  283.     jsr        a6@(-660)            | _LVOSetGadgetAttrsA
  284.  
  285.     moveml    sp@+,a2/a3/a6"
  286.  
  287.     : /* No Output */
  288.     : /* No Input */
  289.     : "d0","d1","a0","a1");
  290. }
  291.  
  292. #endif
  293.  
  294. /* Convert the frame delay to microseconds/seconds */
  295.  
  296. static int usecs, secs;
  297.  
  298. static inline void
  299. convert_fdelay()
  300. {
  301.   usecs = (fdelay % 70) * 14285;
  302.   secs = fdelay / 70;
  303. }
  304.  
  305. /* void SyncWait(unsigned long secs, unsigned long microsecs)
  306.    wait for specified amount of time and then return */
  307.  
  308. static inline void
  309. SyncWait (unsigned long secs, unsigned long microsecs)
  310. {
  311.   struct timeval tv_temp;
  312.  
  313.   tv_temp.tv_secs = secs;
  314.   tv_temp.tv_micro = microsecs;
  315.  
  316.   TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  317.   TimerIO->tr_time = tv_temp;
  318.  
  319.   DoIO ((struct IORequest *) TimerIO);
  320. }
  321.  
  322. /*============================================================================*/
  323.  
  324. static inline void
  325. hrWriteRect (struct HRBitMap *hrbm, UBYTE *buf,
  326.              int srcx,  int srcy,
  327.              int width, int height)
  328. {
  329.     UBYTE *src, *dest;
  330.     int anz, i, mod;
  331.  
  332. /*    UWORD BytesPerRow;
  333.     UWORD Rows;
  334.     UBYTE PixelModulo;
  335.     ULONG ByteSize;
  336.  
  337.     PixelModulo = (hrbm)->PixelModulo;
  338.     Rows = (hrbm)->Rows;
  339.     BytesPerRow = (hrbm)->BytesPerRow;
  340.     ByteSize = (hrbm)->ByteSize;
  341. */
  342.     hrSLockBitMap (hrbm);
  343.  
  344.     if (!srcx && !srcy && (width == InnerWidth) && (height == InnerHeight))
  345.       CopyMemQuick (buf, (hrbm)->MemPtr[0], FrameSize);
  346.     else {
  347.       mod  = srcy*InnerWidth;
  348.       dest = (hrbm)->MemPtr[0] + mod;
  349.       src  = buf + mod;
  350.       i    = width;
  351.  
  352.       /* printf ("srcx: %ld, srcy: %ld, W: %ld, H: %ld, mod: %ld\n",
  353.         srcx, srcy, width, height, mod); */
  354.  
  355.       for (anz = 0; anz < height; anz++,
  356.                                   mod += InnerWidth,
  357.                                   dest = (hrbm)->MemPtr[0] + mod + srcx,
  358.                                   src = buf + mod + srcx,
  359.                                   i = width)
  360.         while (i)
  361.           {*(dest++) = *(src++); i--;}
  362.     }
  363.     hrUnlockBitMap (hrbm);
  364. }
  365.  
  366. /*============================================================================*/
  367.  
  368. int
  369. ASLRequestFile (char *Dir)
  370. {
  371.     struct FileRequester *FileRequester;
  372.     char buffer[256];
  373.     BOOL Result = FALSE;
  374.     struct TagItem tags[6];
  375.     LONG cnt = 0;
  376.  
  377.     SETTAG (ASL_Hail,       "Select FLI/C animation file...");
  378.     SETTAG (ASL_OKText,     "Play");
  379.     SETTAG (ASL_CancelText, "Cancel");
  380.  
  381.     if (Dir && strlen(Dir)) {
  382.         SETTAG (ASL_Dir, Dir);
  383.     }
  384.  
  385.     SETTAG (TAG_END, 0);
  386.  
  387.     if (AslBase = OpenLibrary ("asl.library", 37)) {
  388.         if (FileRequester = (struct FileRequester *) AllocAslRequest (ASL_FileRequest, tags)) {
  389.             if (AslRequest (FileRequester, NULL)) {
  390.                 strcpy (buffer, FileRequester->rf_Dir);
  391.                 AddPart (buffer, FileRequester->rf_File, 255);
  392.                 strcpy (fileName, buffer);
  393.                 Result = TRUE;
  394.             }
  395.             FreeAslRequest (FileRequester);
  396.         }
  397.         CloseLibrary (AslBase);
  398.     }
  399.     return Result;
  400. }
  401.  
  402. /*============================================================================*
  403.  *  Alles ausser den Libraries schliessen und den Speicher wieder freigeben.  *
  404.  *============================================================================*/
  405.  
  406. void
  407. CloseDown (void)
  408. {
  409.     if (fd) {
  410.       Close (fd);
  411.       fd = NULL;
  412.     }
  413.     if (!timerclosed) {
  414.       CloseDevice ((struct IORequest *) TimerIO);
  415.       if (TimerPort) {
  416.         DeleteMsgPort (TimerPort);
  417.         TimerPort = NULL;
  418.       }    
  419.       if (TimerIO) {
  420.         DeleteIORequest ((struct IORequest *) TimerIO);
  421.         TimerIO = NULL;
  422.       }    
  423.       timerclosed = TRUE;
  424.       TimerBase = NULL;
  425.     }
  426.     if (FLI_win) {
  427.       if (Menus) {
  428.           ClearMenuStrip (FLI_win);
  429.           FreeMenus (Menus);
  430.           Menus = NULL;
  431.       }
  432.       if (VisualInfo) {
  433.           FreeVisualInfo (VisualInfo);
  434.           VisualInfo = NULL;
  435.       }
  436.       CloseWindow (FLI_win);
  437.       FLI_win = NULL;
  438.     }
  439.  
  440.     if (hrh) {
  441.  
  442.       hrSwitchSecondView (hrh, FALSE);
  443.  
  444.       if (coltab) {
  445.         hrSetPaletteRGBA (hrh, coltab, 0, 255);
  446.         free (coltab);
  447.         coltab = NULL;
  448.       }
  449.  
  450.       if (curctab) {
  451.         free (curctab);
  452.         curctab = NULL;
  453.       }
  454.  
  455.       hrFreeSecondView(hrh);
  456.       hrh = NULL;
  457.     }
  458.  
  459.     if (UpImage)     DisposeObject (UpImage);
  460.     if (DownImage)   DisposeObject (DownImage);
  461.     if (LeftImage)   DisposeObject (LeftImage);
  462.     if (RightImage)  DisposeObject (RightImage);
  463.     if (LeftGadget)  DisposeObject (LeftGadget);
  464.     if (RightGadget) DisposeObject (RightGadget);
  465.     if (UpGadget)    DisposeObject (UpGadget);
  466.     if (DownGadget)  DisposeObject (DownGadget);
  467.     if (VertGadget)  DisposeObject (VertGadget);
  468.     if (HorizGadget) DisposeObject (HorizGadget);
  469.  
  470.     UpImage = DownImage = LeftImage = RightImage = NULL;
  471.     LeftGadget = RightGadget = HorizGadget = NULL;
  472.     UpGadget   = DownGadget  = VertGadget  = NULL;
  473.  
  474.     if (HRGSystemBase) CloseLibrary(HRGSystemBase);
  475.                        HRGSystemBase = NULL;
  476.     if (HRGRenderBase) CloseLibrary(HRGRenderBase);
  477.                        HRGRenderBase = NULL;
  478.     if (GadToolsBase)  CloseLibrary(GadToolsBase);
  479.                        GadToolsBase = NULL;
  480.     if (IntuitionBase) CloseLibrary((struct Library *) IntuitionBase);
  481.                        IntuitionBase = NULL;
  482.     if (GfxBase)       CloseLibrary((struct Library *) GfxBase);
  483.                        GfxBase = NULL;
  484. }
  485.  
  486. /*============================================================================*
  487.  *  Programm mit einer Fehlermeldung beenden                                  *
  488.  *============================================================================*/
  489.  
  490. void
  491. Quit (int failcode)
  492. {
  493.     char *ErrMsg = "";
  494.  
  495.     if (TimerBase)
  496.         ReadEClock (&time1);    /* find out and display how long it took */
  497.  
  498.     if (!quietFlag) {
  499.         switch (failcode) {
  500.             case NO_ERR  : break;
  501.             case REQ_ERR : break;
  502.             case PAR_ERR : break;
  503.             case MEM_ERR : ErrMsg = "Out of memory"; break;
  504.             case GFX_ERR : ErrMsg = "Need graphics.library V37"; break;
  505.             case INT_ERR : ErrMsg = "Need intuition.library V37"; break;
  506.             case SYS_ERR : ErrMsg = "Need hrgsystem.library V38"; break;
  507.             case REN_ERR : ErrMsg = "Need hrgrender.library V38"; break;
  508.             case DBL_ERR : ErrMsg = "Can't open two PIP Windows"; break;
  509.             case SCR_ERR : ErrMsg = "Can't open Merlin-Screen"; break;
  510.             case WIN_ERR : ErrMsg = "Can't open Window"; break;
  511.             case FND_ERR : ErrMsg = "Can't find Merlin-Screen"; break;
  512.             case PIP_ERR : ErrMsg = "Screen for PIP to small (640x400)"; break;
  513.             case DRI_ERR : ErrMsg = "Can't get ScreenDrawInfo"; break;
  514.             case MPG_ERR : ErrMsg = "This is no FLI/C stream"; break;
  515.             case RNG_ERR : ErrMsg = "Fatal error. Ring buffer full."; break;
  516.             case GET_ERR : ErrMsg = "Unexpected read error."; break;
  517.             case BRK_ERR : ErrMsg = "Interrupted!"; break;
  518.             case GAD_ERR : ErrMsg = "Need gadtools.library V37"; break;
  519.             case VIS_ERR : ErrMsg = "Can't get VisualInfo"; break;
  520.             case MEN_ERR : ErrMsg = "Can't create Menu"; break;
  521.             case TIM_ERR : ErrMsg = "Can't open timer.device"; break;
  522.             default:       ErrMsg = "Unknown error";
  523.         }
  524.         OUTPUT1 ("\n%s\n", ErrMsg);
  525.     }
  526.     if (failcode == NO_ERR && TimerBase)
  527.       printf ("%s: Frames per second = %5.2lf\n", fileName,
  528.                 1000000.0 * totalframes /
  529.                 (((time1.ev_hi - time0.ev_hi) * 4294967296.0
  530.                 + (time1.ev_lo - time0.ev_lo)) * micros_per_eclock));
  531.  
  532.     /* free bitmaps in display list */
  533.  
  534.     disp_cur = &disp_root;
  535.  
  536.     while (disp_cur->disp_next)
  537.     {
  538.         disp_cur = disp_cur->disp_next;
  539.  
  540.         if (disp_cur->disp_pix)
  541.           FreeVec (disp_cur->disp_pix);
  542.     }
  543.     if (map)
  544.       FreeVec (map);
  545.  
  546.     CloseDown ();
  547.     exit (failcode);
  548. }
  549.  
  550. /*============================================================================*
  551.  *  Display allgemein initialisieren durch Oeffnen der Libraries.             *
  552.  *============================================================================*/
  553.  
  554. void
  555. InitLibraries (void)
  556. {
  557.     if (!(GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", 37))) {
  558.         Quit (GFX_ERR);
  559.     }
  560.     if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37))) {
  561.         Quit (INT_ERR);
  562.     }
  563.     if (!(GadToolsBase = (struct Library *) OpenLibrary ("gadtools.library", 37))) {
  564.         Quit (GAD_ERR);
  565.     }
  566.     if (!(HRGSystemBase = (struct Library *) OpenLibrary ("hrgsystem.library", 38))) {
  567.         Quit (SYS_ERR);
  568.     }
  569.     if (!(HRGRenderBase = (struct Library *) OpenLibrary ("hrgrender.library", 38))) {
  570.         Quit (REN_ERR);
  571.     }
  572. }
  573.  
  574. /*============================================================================*
  575.  *  Window und SecondView PIP vergoessern/verkleinern.                        *
  576.  *============================================================================*/
  577.  
  578. static void
  579. Resize (void)
  580. {
  581.     ULONG HorizPot, VertPot, dX, dY;
  582.  
  583.     GetAttr (PGA_Top, HorizGadget, (ULONG *)&HorizPot);
  584.     GetAttr (PGA_Top, VertGadget,  (ULONG *)&VertPot);
  585.  
  586.     hrResizeSecondView (hrh, FLI_win->Width - Screen->WBorLeft - DownImage->Width,
  587.                              FLI_win->Height - (Screen->Font->ta_YSize + Screen->WBorTop + 1) - RightImage->Height);
  588.  
  589.     SetGadAttrs (HorizGadget, FLI_win, NULL,
  590.         PGA_Top,      HorizPot,
  591.         PGA_Visible,  FLI_win->Width,
  592.         PGA_Total,    Width,
  593.         TAG_DONE);
  594.  
  595.     GetAttr (PGA_Top, HorizGadget, (ULONG *)&dX);
  596.  
  597.     SetGadAttrs (VertGadget, FLI_win, NULL,
  598.         PGA_Top,      VertPot,
  599.         PGA_Visible,  FLI_win->Height,
  600.         PGA_Total,    Height,
  601.         TAG_DONE);
  602.  
  603.     GetAttr (PGA_Top, VertGadget, (ULONG *)&dY);
  604.  
  605.     hrScrollSecondView (hrh, dX, dY);
  606.     ScrollX = dX; ScrollY = dY;
  607. }
  608.  
  609. /*============================================================================*
  610.  *  Auf Knopfdruck und Verschieben der Rollbalken reagieren.                  *
  611.  *============================================================================*/
  612.  
  613. static void
  614. CheckGadget (UWORD GadgetID)
  615. {
  616.     int step, HorizPot, VertPot;
  617.     ULONG dX = ScrollX, dY = ScrollY;
  618.  
  619.     switch (GadgetID) {
  620.         case HORIZ_ID: GetAttr (PGA_Top, HorizGadget, (ULONG *)&dX);
  621.                        break;
  622.  
  623.         case LEFT_ID : GetAttr (PGA_Top, HorizGadget, (ULONG *)&HorizPot);
  624.                        step = max (HorizPot - WIDTH_STEP, 0);
  625.                        SetGadAttrs(HorizGadget, FLI_win, NULL,
  626.                            PGA_Top,      step,
  627.                            PGA_Visible,  FLI_win->Width,
  628.                            PGA_Total,    Width,
  629.                            TAG_DONE);
  630.                        GetAttr (PGA_Top, HorizGadget, (ULONG *)&dX);
  631.                        break;
  632.  
  633.         case RIGHT_ID: GetAttr (PGA_Top, HorizGadget, (ULONG *)&HorizPot);
  634.                        step = min (HorizPot + WIDTH_STEP, Width);
  635.                        SetGadAttrs(HorizGadget, FLI_win, NULL,
  636.                            PGA_Top,      step,
  637.                            PGA_Visible,  FLI_win->Width,
  638.                            PGA_Total,    Width,
  639.                            TAG_DONE);
  640.                        GetAttr (PGA_Top, HorizGadget, (ULONG *)&dX);
  641.                        break;
  642.  
  643.         case VERT_ID : GetAttr (PGA_Top, VertGadget, (ULONG *)&dY);
  644.                        break;
  645.  
  646.         case UP_ID   : GetAttr (PGA_Top, VertGadget,  (ULONG *)&VertPot);
  647.                        step = max (VertPot - HEIGHT_STEP, 0);
  648.                        SetGadAttrs(VertGadget, FLI_win, NULL,
  649.                            PGA_Top,      step,
  650.                            PGA_Visible,  FLI_win->Height,
  651.                            PGA_Total,    Height,
  652.                            TAG_DONE);
  653.                        GetAttr (PGA_Top, VertGadget, (ULONG *)&dY);
  654.                        break;
  655.  
  656.         case DOWN_ID : GetAttr (PGA_Top, VertGadget,  (ULONG *)&VertPot);
  657.                        step = min (VertPot + HEIGHT_STEP, Height);
  658.                        SetGadAttrs(VertGadget, FLI_win, NULL,
  659.                            PGA_Top,      step,
  660.                            PGA_Visible,  FLI_win->Height,
  661.                            PGA_Total,    Height,
  662.                            TAG_DONE);
  663.                        GetAttr (PGA_Top, VertGadget, (ULONG *)&dY);
  664.                        break;
  665.     }
  666.     if ((dX != ScrollX) || (dY != ScrollY)) {
  667.       hrScrollSecondView (hrh, dX, dY);
  668.       ScrollX = dX; ScrollY = dY;
  669.     }
  670. }
  671.  
  672. /*============================================================================*
  673.  *  Auf Tastendruck reagieren.                                                *
  674.  *============================================================================*/
  675.  
  676. static void
  677. CheckKey (UWORD KeyID, ULONG Qualifier)
  678. {
  679.     int step, HorizPot, VertPot;
  680.  
  681.     ULONG dX = ScrollX, dY = ScrollY;
  682.  
  683.     onestep = stepflag;    /* 1 if we should be loop waiting for a step */
  684.  
  685.     switch (KeyID) {
  686.         case KEY_LEFT:  GetAttr (PGA_Top, HorizGadget, (ULONG *)&HorizPot);
  687.                         if (SHIFT_KEY(Qualifier)) {
  688.                             step = max (HorizPot - FLI_win->Width, 0);
  689.                         } else {
  690.                             step = max (HorizPot - WIDTH_STEP, 0);
  691.                         }
  692.                         SetGadAttrs(HorizGadget, FLI_win, NULL,
  693.                             PGA_Top,      step,
  694.                             PGA_Visible,  FLI_win->Width,
  695.                             PGA_Total,    Width,
  696.                             TAG_DONE);
  697.                         GetAttr (PGA_Top, HorizGadget, (ULONG *)&dX);
  698.                         break;
  699.  
  700.         case KEY_RIGHT: GetAttr (PGA_Top, HorizGadget, (ULONG *)&HorizPot);
  701.                         if (SHIFT_KEY(Qualifier)) {
  702.                             step = min (HorizPot + FLI_win->Width, Width);
  703.                         } else {
  704.                             step = min (HorizPot + WIDTH_STEP, Width);
  705.                         }
  706.                         SetGadAttrs(HorizGadget, FLI_win, NULL,
  707.                             PGA_Top,      step,
  708.                             PGA_Visible,  FLI_win->Width,
  709.                             PGA_Total,    Width,
  710.                             TAG_DONE);
  711.                         GetAttr (PGA_Top, HorizGadget, (ULONG *)&dX);
  712.                         break;
  713.  
  714.         case KEY_UP:    GetAttr (PGA_Top, VertGadget,  (ULONG *)&VertPot);
  715.                         if (SHIFT_KEY(Qualifier)) {
  716.                             step = max (VertPot - FLI_win->Height, 0);
  717.                         } else {
  718.                             step = max (VertPot - HEIGHT_STEP, 0);
  719.                         }
  720.                         SetGadAttrs(VertGadget, FLI_win, NULL,
  721.                             PGA_Top,      step,
  722.                             PGA_Visible,  FLI_win->Height,
  723.                             PGA_Total,    Height,
  724.                             TAG_DONE);
  725.                         GetAttr (PGA_Top, VertGadget, (ULONG *)&dY);
  726.                         break;
  727.  
  728.         case KEY_DOWN:  GetAttr (PGA_Top, VertGadget,  (ULONG *)&VertPot);
  729.                         if (SHIFT_KEY(Qualifier)) {
  730.                             step = min (VertPot + FLI_win->Height, Height);
  731.                         } else {
  732.                             step = min (VertPot + HEIGHT_STEP, Height);
  733.                         }
  734.                         SetGadAttrs(VertGadget, FLI_win, NULL,
  735.                             PGA_Top,      step,
  736.                             PGA_Visible,  FLI_win->Height,
  737.                             PGA_Total,    Height,
  738.                             TAG_DONE);
  739.                         GetAttr (PGA_Top, VertGadget, (ULONG *)&dY);
  740.                         break;
  741.  
  742.         case KEY_MINUS:    fdelay++;            /* Minus: Slow down */
  743.                         convert_fdelay();
  744.                         break;
  745.  
  746.  
  747.         case KEY_PLUS:    if (fdelay)            /* Plus: Speed up */
  748.                           fdelay--;
  749.                         convert_fdelay();
  750.                         break;
  751.  
  752.         case KEY_SPACE:    stepflag = 1;        /* Space: Single step */
  753.                         onestep = 0;
  754.                         break;
  755.  
  756.         case KEY_c:        stepflag = 0;        /* 'c': Continue animation */
  757.                         onestep = 0;
  758.                         break;
  759.  
  760.         case KEY_q:        Quit (NO_ERR);        /* 'q': Quit */
  761.                         break;
  762.     }
  763.  
  764.     if ((dX != ScrollX) || (dY != ScrollY)) {
  765.       hrScrollSecondView (hrh, dX, dY);
  766.       ScrollX = dX; ScrollY = dY;
  767.     }
  768. }
  769.  
  770. /*============================================================================*
  771.  *  Auf Menuewahl reagieren.                                                  *
  772.  *============================================================================*/
  773.  
  774. static void
  775. ChangeWindow (int x, int y, int w, int h)
  776. {
  777.     int dx, dy;
  778.  
  779.     dx = x - FLI_win->LeftEdge;
  780.     dy = y - FLI_win->TopEdge;
  781.  
  782.     if (dx || dy ) {
  783.       MoveWindow (FLI_win, dx, dy);
  784.       hrMoveSecondView (hrh, FLI_win->LeftEdge + left, FLI_win->TopEdge + top);
  785.     }
  786.     dx = w - FLI_win->Width;
  787.     dy = h - FLI_win->Height;
  788.  
  789.     if (dx || dy ) {
  790.       SizeWindow (FLI_win, dx, dy);
  791.       Resize ();
  792.     }
  793. }
  794.  
  795. static void
  796. ResetWindow (void)
  797. {
  798.     int ox, oy;
  799.  
  800.     ox = (hrh->ModeInfo->ResWidth  - InnerWidth) / 2;
  801.     oy = (hrh->ModeInfo->ResHeight - InnerHeight) / 2;
  802.  
  803.     ChangeWindow (ox, oy, FLI_win->MaxWidth, FLI_win->MaxHeight);
  804. }
  805.  
  806. static void
  807. CheckMenu (UWORD MenuNumber)
  808. {
  809.  UWORD ItemNum;
  810.  struct MenuItem *Item;
  811.  char envbuf[32], *envbuf2;
  812.  int winx, winy,
  813.      winw, winh;
  814.  
  815.  while (MenuNumber != MENUNULL) {
  816.       Item = (struct MenuItem *) ItemAddress (Menus, MenuNumber);
  817.       ItemNum = ITEMNUM (MenuNumber);
  818.  
  819.       switch (MENUNUM (MenuNumber)) {
  820.        case 0: switch (ItemNum) {
  821.  
  822.          case 0: EasyReqArgs (FLI_win, &AboutRequest, NULL, (LONG *) NULL);
  823.                  break;
  824.  
  825.          case 2: Quit (NO_ERR);
  826.        }
  827.        break;
  828.  
  829.        case 1: switch (ItemNum) {
  830.          case 0: ResetWindow ();
  831.                  break;
  832.          case 1: sprintf (envbuf ,"%s=%ld %ld %ld %ld", ENVNAME,
  833.                             FLI_win->LeftEdge, FLI_win->TopEdge,
  834.                             FLI_win->Width, FLI_win->Height);
  835.                  break;
  836.          case 2: ResetWindow ();
  837.                  break;
  838.          case 4: ChangeWindow (FLI_win->LeftEdge, FLI_win->TopEdge,
  839.                                FLI_win->MinWidth, FLI_win->MinHeight);
  840.                  break;
  841.          case 5: ChangeWindow  (min (FLI_win->WScreen->Width  - FLI_win->MaxWidth,
  842.                                 FLI_win->LeftEdge),
  843.                                 min (FLI_win->WScreen->Height - FLI_win->MaxHeight,
  844.                                 FLI_win->TopEdge),
  845.                                 FLI_win->MaxWidth, FLI_win->MaxHeight);
  846.                  break;
  847.        }
  848.        break;
  849.       }
  850.       MenuNumber = Item->NextSelect;
  851.  }
  852. }
  853.  
  854. /*============================================================================*
  855.  *  Rollbalken und Pfeilknoepfe erzeugen.                                     *
  856.  *============================================================================*/
  857.  
  858. static void
  859. AddGadgets (void)
  860. {
  861.     static struct TagItem ArrowMappings[] = { GA_ID, GA_ID, TAG_END };
  862.     struct DrawInfo *DrawInfo;
  863.     BOOL Borderless = FALSE;
  864.     int ImageSize;
  865.     UWORD Border;
  866.     ULONG Mode;
  867.  
  868.     Mode = GetVPModeID (&Screen->ViewPort);
  869.  
  870.     if (Mode == INVALID_ID) {
  871.         Mode = HIRES_KEY;
  872.     }
  873.     if ((Mode & HIRES_KEY) || ((Mode & MONITOR_ID_MASK) == MERLIN_KEY)) {    /* get system images */
  874.         ImageSize = SYSISIZE_MEDRES;
  875.         Border = 4;
  876.     } else {
  877.         ImageSize = SYSISIZE_LOWRES;
  878.         Border = 3;
  879.     }
  880.  
  881.     if (!(DrawInfo = (struct DrawInfo *) GetScreenDrawInfo (Screen)))
  882.         Quit (DRI_ERR);
  883.  
  884.     UpImage = (struct Image *) NewObject (NULL, "sysiclass",
  885.         SYSIA_Size,     ImageSize,
  886.         SYSIA_Which,    UPIMAGE,
  887.         SYSIA_DrawInfo, DrawInfo,
  888.         TAG_END);
  889.     DownImage = (struct Image *) NewObject (NULL, "sysiclass",
  890.         SYSIA_Size,     ImageSize,
  891.         SYSIA_Which,    DOWNIMAGE,
  892.         SYSIA_DrawInfo, DrawInfo,
  893.         TAG_END);
  894.     LeftImage = (struct Image *) NewObject (NULL, "sysiclass",
  895.         SYSIA_Size,     ImageSize,
  896.         SYSIA_Which,    LEFTIMAGE,
  897.         SYSIA_DrawInfo, DrawInfo,
  898.         TAG_END);
  899.     RightImage = (struct Image *) NewObject (NULL, "sysiclass",
  900.         SYSIA_Size,     ImageSize,
  901.         SYSIA_Which,    RIGHTIMAGE,
  902.         SYSIA_DrawInfo, DrawInfo,
  903.         TAG_END);
  904.  
  905.     FreeScreenDrawInfo (Screen, DrawInfo);
  906.  
  907.     if (!UpImage || !DownImage || !LeftImage || !RightImage)
  908.         Quit (MEM_ERR);
  909.  
  910.     if ((SysBase->LibNode.lib_Version >= 39) &&        /* OS2.0 und Mono Roll- */
  911.         (Screen->RastPort.BitMap->Depth > 1)) {        /* balken verbessern */
  912.         Borderless = TRUE;
  913.     }
  914.     VertGadget = NewObject (NULL,"propgclass",
  915.         GA_ID,          VERT_ID,
  916.         GA_RelHeight,   - (UpImage->Height + DownImage->Height + RightImage->Height + (Screen->Font->ta_YSize + Screen->WBorTop + 1)) - 2,
  917.         GA_Width,       DownImage->Width - 2 * Border,
  918.         GA_Top,         (Screen->Font->ta_YSize + Screen->WBorTop + 1) + 1,
  919.         GA_RelRight,    - (DownImage->Width - 2 * Border) - Border + 1,
  920.         GA_Immediate,   TRUE,
  921.         GA_FollowMouse, TRUE,
  922.         GA_RelVerify,   TRUE,
  923.         GA_RightBorder, TRUE,
  924.         PGA_Borderless, Borderless,
  925.         PGA_Freedom,    FREEVERT,
  926.         PGA_NewLook,    TRUE,
  927.         PGA_Visible,    1,
  928.         PGA_Total,      1,
  929.         TAG_DONE);
  930.  
  931.     UpGadget = NewObject (NULL,"buttongclass",
  932.         GA_ID,          UP_ID,
  933.         GA_Image,       UpImage,
  934.         GA_Width,       UpImage->Width,
  935.         GA_Height,      UpImage->Height,
  936.         GA_RelBottom,   1 - RightImage->Height - DownImage->Height - UpImage->Height,
  937.         GA_RelRight,    1 - UpImage->Width,
  938.         GA_Immediate,   TRUE,
  939.         GA_RelVerify,   TRUE,
  940.         GA_Previous,    VertGadget,
  941.         GA_RightBorder, TRUE,
  942.         ICA_TARGET,     ICTARGET_IDCMP,
  943.         ICA_MAP,        ArrowMappings,
  944.         TAG_DONE);
  945.  
  946.     DownGadget = NewObject (NULL,"buttongclass",
  947.         GA_ID,          DOWN_ID,
  948.         GA_Image,       DownImage,
  949.         GA_Width,       DownImage->Width,
  950.         GA_Height,      DownImage->Height,
  951.         GA_RelBottom,   1 - RightImage->Height - DownImage->Height,
  952.         GA_RelRight,    1 - DownImage->Width,
  953.         GA_Immediate,   TRUE,
  954.         GA_RelVerify,   TRUE,
  955.         GA_Previous,    UpGadget,
  956.         GA_RightBorder, TRUE,
  957.         ICA_TARGET,     ICTARGET_IDCMP,
  958.         ICA_MAP,        ArrowMappings,
  959.         TAG_DONE);
  960.  
  961.     HorizGadget = NewObject (NULL,"propgclass",
  962.         GA_ID,          HORIZ_ID,
  963.         GA_RelWidth,    - (LeftImage->Width + RightImage->Width + DownImage->Width + Screen->WBorLeft) - 1,
  964.         GA_Height,      RightImage->Height - 2 * 2,
  965.         GA_RelBottom,   - (RightImage->Height - 2 * 2) - 1,
  966.         GA_Left,        Screen->WBorLeft - 1,
  967.         GA_Immediate,   TRUE,
  968.         GA_FollowMouse, TRUE,
  969.         GA_RelVerify,   TRUE,
  970.         GA_Previous,    DownGadget,
  971.         GA_BottomBorder,TRUE,
  972.         PGA_Borderless, Borderless,
  973.         PGA_Freedom,    FREEHORIZ,
  974.         PGA_NewLook,    TRUE,
  975.         PGA_Visible,    1,
  976.         PGA_Total,      1,
  977.         TAG_DONE);
  978.  
  979.     LeftGadget = NewObject (NULL,"buttongclass",
  980.         GA_ID,          LEFT_ID,
  981.         GA_Image,       LeftImage,
  982.         GA_RelRight,    1 - DownImage->Width - RightImage->Width - LeftImage->Width,
  983.         GA_RelBottom,   1 - LeftImage->Height,
  984.         GA_Height,      LeftImage->Height,
  985.         GA_Width,       LeftImage->Width,
  986.         GA_Immediate,   TRUE,
  987.         GA_RelVerify,   TRUE,
  988.         GA_Previous,    HorizGadget,
  989.         GA_BottomBorder,TRUE,
  990.         ICA_TARGET,     ICTARGET_IDCMP,
  991.         ICA_MAP,        ArrowMappings,
  992.         TAG_DONE);
  993.  
  994.     RightGadget = NewObject (NULL,"buttongclass",
  995.         GA_ID,          RIGHT_ID,
  996.         GA_Image,       RightImage,
  997.         GA_Width,       RightImage->Width,
  998.         GA_Height,      RightImage->Height,
  999.         GA_RelBottom,   1 - RightImage->Height,
  1000.         GA_RelRight,    1 - DownImage->Width - RightImage->Width,
  1001.         GA_Immediate,   TRUE,
  1002.         GA_RelVerify,   TRUE,
  1003.         GA_Previous,    LeftGadget,
  1004.         GA_BottomBorder,TRUE,
  1005.         ICA_TARGET,     ICTARGET_IDCMP,
  1006.         ICA_MAP,        ArrowMappings,
  1007.         TAG_DONE);
  1008.  
  1009.     if (!LeftGadget || !RightGadget || !HorizGadget ||
  1010.         !UpGadget   || !DownGadget  || !VertGadget)
  1011.             Quit (MEM_ERR);
  1012.  
  1013.     /* Windowgroesse (Brutto) */
  1014.  
  1015.     Width  = InnerWidth + Screen->WBorLeft + DownImage->Width;
  1016.     Height = InnerHeight + (Screen->Font->ta_YSize + Screen->WBorTop + 1) + RightImage->Height;
  1017. }
  1018.  
  1019. /*============================================================================*
  1020.  *  Oeffnen eines Windows mit einem SecondView PIP.                           *
  1021.  *============================================================================*/
  1022.  
  1023. static char *
  1024. GetBaseName (char *name)
  1025. {
  1026.     char *fname;
  1027.  
  1028.     if (name) {
  1029.         if (name[strlen(name)-1] == '/') {
  1030.             name[strlen(name)-1] = '\0';
  1031.         }
  1032.         if (fname = strrchr (name, '/')) {
  1033.             return fname+1;
  1034.         } else if (fname = strrchr (name, ':')) {
  1035.             return fname+1;
  1036.         }
  1037.         return name;
  1038.     }
  1039.     return version+6;
  1040. }
  1041.  
  1042. static void
  1043. OpenMerlinPIP (int w, int h)
  1044. {
  1045.     struct TagItem tags[17];
  1046.     struct HRList *hrl;
  1047.     struct HRHandle *hrh2;
  1048.     LONG cnt;
  1049.     char *envbuf;
  1050.     int ox, oy, winx, winy, winw, winh;
  1051.  
  1052.     hrl = hrLockHRList();
  1053.     hrh2 = hrl->laston;
  1054.     hrUnlockHRList (hrl);
  1055.  
  1056.     if (!hrh2 || !(Screen = hrh2->IScr)) {    /* Richtigen IntuiScreen suchen */
  1057.       Quit (FND_ERR);
  1058.     }
  1059.     if (hrh2->SecondView != NULL) {            /* Nur ein PIP erlaubt */
  1060.       Quit (DBL_ERR);
  1061.     }
  1062.     if ((hrh2->ModeInfo->ResWidth < 640) || (hrh2->ModeInfo->ResHeight < 400)) {
  1063.       Quit (PIP_ERR);
  1064.     }
  1065.  
  1066.     AddGadgets();
  1067.  
  1068.     left = Screen->WBorLeft;
  1069.     top  = Screen->Font->ta_YSize + Screen->WBorTop + 1;
  1070.  
  1071.     ox = (hrh2->ModeInfo->ResWidth  - w) / 2;
  1072.     oy = (hrh2->ModeInfo->ResHeight - h) / 2;
  1073.  
  1074.     cnt = 0;
  1075.     SETTAG (WA_Left,        ox - left);
  1076.     SETTAG (WA_Top,            oy - top);
  1077.     SETTAG (WA_Width,        Width);
  1078.     SETTAG (WA_Height,        Height);
  1079.  
  1080.     SETTAG (WA_Title,       GetBaseName(fileName));
  1081.     SETTAG (WA_PubScreen,   Screen);
  1082.     SETTAG (WA_MaxWidth,    Width);
  1083.     SETTAG (WA_MaxHeight,   Height);
  1084.     SETTAG (WA_MinWidth,    MIN_WIDTH);
  1085.     SETTAG (WA_MinHeight,   MIN_HEIGHT);
  1086.     SETTAG (WA_IDCMP,       IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_RAWKEY |
  1087.                             IDCMP_INTUITICKS | IDCMP_CLOSEWINDOW | IDCMP_MENUPICK |
  1088.                             IDCMP_CHANGEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_ACTIVEWINDOW);
  1089.     SETTAG (WA_Flags,       WFLG_SIZEGADGET | WFLG_SIZEBRIGHT | WFLG_SIZEBBOTTOM | WFLG_ACTIVATE |
  1090.                             WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET );
  1091.     SETTAG (WA_Gadgets,     VertGadget);
  1092.     SETTAG (WA_ScreenTitle, version+6);
  1093.     SETTAG (WA_NewLookMenus,TRUE);
  1094.     SETTAG (TAG_END,        0);
  1095.  
  1096.     if (!(FLI_win = OpenWindowTagList (NULL, tags))) {  /* Window oeffnen */
  1097.       Quit (WIN_ERR);
  1098.     }
  1099.     rp = FLI_win->RPort;
  1100.  
  1101.     if (!(coltab = (ULONG *) malloc (256 * sizeof(ULONG))) ||
  1102.         (!(curctab = (ULONG *) malloc (256 * sizeof(ULONG)) )))
  1103.     {
  1104.       Quit (MEM_ERR);
  1105.     }
  1106.  
  1107.     hrGetPaletteRGBA (hrh2, coltab, 0, 255);    /* Farbpalette retten */
  1108.  
  1109.     hrAllocSecondView (hrh2, w, h, 0);            /* PIP erzeugen */
  1110.  
  1111.     hrh = hrh2;
  1112.     hrbm = &hrh->SecondView->BitMap;
  1113.  
  1114.     hrClearToCol (hrbm, 1);
  1115.  
  1116.     hrMoveSecondView (hrh, FLI_win->LeftEdge + left,
  1117.                            FLI_win->TopEdge  + top);
  1118.     Resize ();
  1119.  
  1120.     if (!(Menus = (struct Menu *) CreateMenus (NewMenu, TAG_DONE)))
  1121.       Quit (MEN_ERR);
  1122.  
  1123.     if (!(VisualInfo = (APTR) GetVisualInfo (Screen, TAG_DONE)))
  1124.       Quit (VIS_ERR);
  1125.  
  1126.     LayoutMenus (Menus, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE);
  1127.     SetMenuStrip (FLI_win, Menus);
  1128.  
  1129.     hrSwitchSecondView (hrh, TRUE);
  1130. }
  1131.  
  1132. /*============================================================================*/
  1133.  
  1134. /* Print a usage message and exit */
  1135.  
  1136. static void
  1137. usage()
  1138. {
  1139.     Printf ("Usage: MerlinFLI [-v] [-r<count>] [-d<delay>] [-n] fli_file\n");
  1140.     Printf ("-v        Verbose Debugging info\n"
  1141.             "-r<count> Repeat count times (0 = loop forever)\n"
  1142.             "-d<delay> Delay between frames in 1/70s\n"
  1143.             "-n        Don't interpret file before display"
  1144.             " (slower but uses less memory)\n");
  1145.     Quit (NO_ERR);
  1146. }
  1147.  
  1148. /* Function to display the interpretation immediately */
  1149.  
  1150. static void
  1151. func_disp  (int ftype, int frame, unsigned char *buf,
  1152.             int srcx,  int srcy,
  1153.             int destx, int desty,
  1154.             int swidth,int sheight)
  1155. {
  1156.     static int colchange = FALSE;    /* Colormap has changed */
  1157.     static int cols, cole;            /* Start-/End-Index der Farben */
  1158.  
  1159.     switch (ftype)
  1160.     {
  1161.         case FLI_COPY:
  1162.         case FLI_LC:
  1163.         case FLI_DELTA:
  1164.         case FLI_BRUN:
  1165.  
  1166. /*============================================================================*
  1167.  *          Direkt in SecondView-BitMap mit/ohne Offsets kopieren.            *
  1168.  *============================================================================*/
  1169.  
  1170.             CopyMemQuick (buf, (hrbm)->MemPtr[0], FrameSize);
  1171.  
  1172.             /* hrWriteRect (hrbm, buf, srcx, srcy, swidth, sheight); */
  1173.  
  1174.             break;
  1175.  
  1176.         case FLI_BLACK:
  1177.             hrClearToCol (hrbm, 1);
  1178.             break;
  1179.  
  1180.         case FLI_COLOR:
  1181.             cols = srcx;  
  1182.             cole = srcx+srcy-1;  
  1183.  
  1184.             while (srcy--)
  1185.             {
  1186.                 ULONG tmp;
  1187.                 tmp  = (*(buf++) & 0x3f) << (2+24);
  1188.                 tmp |= (*(buf++) & 0x3f) << (2+16);
  1189.                 tmp |= (*(buf++) & 0x3f) << (2+ 8);
  1190.                 curctab [srcx] = tmp;
  1191.                 srcx++;
  1192.             }
  1193.             colchange = TRUE;
  1194.             break;
  1195.  
  1196.         case FLI_256_COLOR:
  1197.             cols = srcx;  
  1198.             cole = srcx+srcy-1;  
  1199.  
  1200.             while (srcy--)
  1201.             {
  1202.                 ULONG tmp;    
  1203.                 tmp  = *(buf++) << 24;
  1204.                 tmp |= *(buf++) << 16;
  1205.                 tmp |= *(buf++) <<  8;
  1206.                 curctab [srcx] = tmp;
  1207.                 srcx++;
  1208.             }
  1209.             colchange = TRUE;
  1210.             break;
  1211.  
  1212.         case FLI_SYNC:
  1213.             if (colchange)
  1214.             {
  1215.                 hrSetPaletteRGBA (hrh, curctab, cols, cole);
  1216.                 colchange = FALSE;
  1217.             }
  1218.  
  1219.             do {
  1220.                 CheckWindow (FLI_win);
  1221.             } while (stepflag && onestep);
  1222.  
  1223.             if (usecs || secs)        /* wait for frame delay */
  1224.               SyncWait (secs, usecs);
  1225.  
  1226.             break;
  1227.     }
  1228. }
  1229.  
  1230. /* Store the interpretation */
  1231.  
  1232. static void
  1233. func_interp(int ftype,            /* The type of this chunk */
  1234.             int frame,            /* The number of this frame */
  1235.             unsigned char *buf, /* A pointer to the pixel/colormap data */
  1236.             int srcx,            /* The upper left corner in the data array */
  1237.             int srcy,            /* The upper left corner in the window */
  1238.             int destx,            /* The dimensions of the rectangle */
  1239.             int desty,
  1240.             int swidth,int sheight)
  1241. {
  1242.     ULONG *coltmp;    /* Temporary storage for pointer to Color struct */
  1243.  
  1244.     /* set title of window to current frame number */
  1245.  
  1246.     static char framenum[32];
  1247.     sprintf(framenum, "Load: Frame %ld", disp_cur->disp_frame);
  1248.  
  1249.     SetWindowTitles (FLI_win, framenum, (char *)-1);
  1250.  
  1251.     /* Allocate another element in the display list */
  1252.  
  1253.     disp_cur->disp_next = (struct disp_list *)malloc(sizeof(struct disp_list));
  1254.     disp_cur = disp_cur->disp_next;
  1255.  
  1256.     /* Clear the pointer to the next element so we find the end of the list */
  1257.  
  1258.     disp_cur->disp_next = (struct disp_list *)0;
  1259.  
  1260.     /* Copy info pertaining to all or most of the chunks */
  1261.  
  1262.     disp_cur->disp_type = ftype;
  1263.     disp_cur->disp_frame = frame;
  1264.     disp_cur->disp_width = swidth;
  1265.     disp_cur->disp_height = sheight;
  1266.     disp_cur->disp_destx = destx;
  1267.     disp_cur->disp_desty = desty;
  1268.     disp_cur->disp_pix = (UBYTE *)NULL;
  1269.  
  1270.     switch (ftype)
  1271.     {
  1272.         case FLI_COPY:
  1273.         case FLI_LC:
  1274.         case FLI_DELTA:
  1275.         case FLI_BRUN:
  1276.  
  1277.             if (!(disp_cur->disp_pix = AllocVec (FrameSize, MEMF_CLEAR|MEMF_ANY)))
  1278.               Quit (MEM_ERR);
  1279.  
  1280.             CopyMemQuick (buf, disp_cur->disp_pix, FrameSize);
  1281.             break;
  1282.  
  1283.         case FLI_COLOR:
  1284.  
  1285.             /* Create an array of Color to hold the colors.
  1286.                Specific to FLI_COLOR:
  1287.                srcx is the starting color index and
  1288.                srcy is the number of colors
  1289.             */
  1290.  
  1291.             if (!(coltmp = (ULONG *) malloc (srcy * sizeof(ULONG))))
  1292.               Quit (MEM_ERR);
  1293.  
  1294.             disp_cur->disp_cols = coltmp;
  1295.             disp_cur->disp_begcol = srcx;
  1296.             disp_cur->disp_numcol = srcy;
  1297.  
  1298.             /* Copy the changed colors to the Color array */
  1299.  
  1300.             while (srcy--)
  1301.             {
  1302.                 ULONG tmp;
  1303.                 tmp  = (*(buf++) & 0x3f) << (2+24);
  1304.                 tmp |= (*(buf++) & 0x3f) << (2+16);
  1305.                 tmp |= (*(buf++) & 0x3f) << (2+ 8);
  1306.                 tmp |= (UBYTE) srcx;                /* Pixel Nr. Na ja...*/
  1307.                 coltmp [srcx] = tmp;
  1308.                 srcx++;
  1309.             }
  1310.             break;
  1311.  
  1312.         case FLI_256_COLOR:
  1313.  
  1314.             /*    Create an array of Color to hold the colors.
  1315.                 Specific to FLI_256_COLOR:
  1316.                 srcx is the starting color index and
  1317.                 srcy is the number of colors */
  1318.  
  1319.             if (!(coltmp = (ULONG *) malloc (srcy * sizeof(ULONG))))
  1320.               Quit (MEM_ERR);
  1321.  
  1322.             disp_cur->disp_cols = coltmp;
  1323.             disp_cur->disp_begcol = srcx;
  1324.             disp_cur->disp_numcol = srcy;
  1325.  
  1326.             /* Copy the changed colors to the Color array */
  1327.  
  1328.             while (srcy--)
  1329.             {
  1330.                 ULONG tmp;
  1331.                 tmp  = *(buf++) << 24;
  1332.                 tmp |= *(buf++) << 16;
  1333.                 tmp |= *(buf++) <<  8;
  1334.                 tmp |= (UBYTE) srcx;                /* Pixel Nr. Na ja...*/
  1335.                 coltmp [srcx] = tmp;
  1336.                 srcx++;
  1337.             }
  1338.             break;
  1339.  
  1340.         /* FLI_BLACK and FLI_SYNC only need to be stored */
  1341.  
  1342.         case FLI_BLACK:
  1343.         case FLI_SYNC:
  1344.             break;
  1345.     }
  1346. }
  1347.  
  1348. /* Display the stored interpretation */
  1349.  
  1350. static void
  1351. display_interp (struct disp_list *dc)    /* The structure holding the info on the chunk */
  1352. {
  1353.     static int colchange = FALSE;    /* Colormap has changed */
  1354.     int idx, pixel, numcols;
  1355.     int swidth, sheight;        /* Dimension of the changing rectangle */
  1356.     int destx, desty;            /* Upper left corner of the rectangle */
  1357.  
  1358.     static int cols, cole;        /* Start-/End-Index der Farben */
  1359.  
  1360.     swidth = dc->disp_width;    /* Copy some fields from the structure */
  1361.     sheight = dc->disp_height;
  1362.     destx = dc->disp_destx;
  1363.     desty = dc->disp_desty;
  1364.  
  1365.     switch (dc->disp_type)
  1366.     {
  1367.         case FLI_COPY:
  1368.         case FLI_LC:
  1369.         case FLI_DELTA:
  1370.         case FLI_BRUN:
  1371.  
  1372.             CopyMemQuick (dc->disp_pix, (hrbm)->MemPtr[0], FrameSize);
  1373.  
  1374.             /* hrWriteRect (hrbm, dc->disp_pix, destx, desty, swidth, sheight); */
  1375.  
  1376.             break;
  1377.  
  1378.         case FLI_BLACK:
  1379.  
  1380.             /* Clear the whole rectangle */
  1381.  
  1382.             hrClearToCol (hrbm, 1);        /* Pen 0 ?? */
  1383.             break;
  1384.  
  1385.         case FLI_COLOR:
  1386.         case FLI_256_COLOR:
  1387.  
  1388.             /* Store the changed colors in the colormap and note that */
  1389.  
  1390.             cols = dc->disp_begcol;  
  1391.             cole = dc->disp_begcol+dc->disp_numcol-1;  
  1392.  
  1393.             idx = 0;
  1394.             numcols = dc->disp_numcol;
  1395.  
  1396.             while (numcols--)
  1397.             {
  1398.                 pixel = dc->disp_cols[idx] & 0xffL;    /* Pixel Nr. Na ja...*/
  1399.  
  1400.                 curctab[pixel] = dc->disp_cols[idx] & ~0xffL;
  1401.                 idx++;
  1402.             }
  1403.             colchange = TRUE;
  1404.             break;
  1405.  
  1406.         case FLI_SYNC:
  1407.  
  1408.             /* If the colors have changed we set the colormap for the window */
  1409.  
  1410.             if (colchange)
  1411.             {
  1412.                 hrSetPaletteRGBA (hrh, curctab, cols, cole);
  1413.                 colchange = 0;
  1414.             }
  1415.  
  1416.             do {
  1417.                 CheckWindow (FLI_win);
  1418.             } while (stepflag && onestep);
  1419.  
  1420.             if (usecs || secs)            /* wait for frame delay */
  1421.               SyncWait (secs, usecs);
  1422.  
  1423.             break;
  1424.     }
  1425. }
  1426.  
  1427. /*============================================================================*
  1428.  * Main :)
  1429.  *============================================================================*/
  1430.  
  1431. int main (int argc, char *argv[])
  1432. {
  1433.     struct fli_header header;    /* To hold the main header */
  1434.     unsigned char *data;        /* Always has the current image data */
  1435.     int repeatcount;            /* How many times to loop */
  1436.     unsigned char notfirst;        /* Is this not the first time through? */
  1437.     ULONG mem;
  1438.  
  1439.     fdelay = -1;
  1440.     repeatcount = 10;
  1441.  
  1442.     /* required very early for (possible) error handling */
  1443.  
  1444.     disp_root.disp_next = (struct disp_list *)0;
  1445.  
  1446.     while (--argc && argv[1][0] == '-')
  1447.     {
  1448.         argv++;
  1449.         switch (argv[0][1])
  1450.         {
  1451.             case 'r':
  1452.                 repeatcount = atol(&(argv[0][2]));
  1453.                 break;
  1454.             case 'd':
  1455.                 fdelay = atol(&(argv[0][2]));
  1456.                 break;
  1457.             case 'n':
  1458.                 flag_noint = 1;
  1459.                 break;
  1460.             case 'v':
  1461.                 verbose = 1;
  1462.                 break;
  1463.             default:
  1464.                 usage();
  1465.         }
  1466.     }
  1467.  
  1468.     if (argc == 1 && argv[1][0] == '?')
  1469.         usage();
  1470.  
  1471.     /*    if (!verbose)
  1472.         quietFlag = TRUE; */
  1473.  
  1474.     if (argc != 1) {
  1475.       if (!ASLRequestFile (NULL))
  1476.         usage();
  1477.     }
  1478.     else {
  1479.         strcpy (fileName, argv[1]);
  1480.     }  
  1481.  
  1482.     stdout = Output();
  1483.  
  1484.     if (!(fd = Open (fileName, MODE_OLDFILE)))
  1485.     {
  1486.         Printf ("Error opening '%s'", fileName);
  1487.         Quit (GET_ERR);
  1488.     }
  1489.     read_flihead (fd, &header);        /* Read the main FLI header */
  1490.  
  1491.     if (((header.fhd_magic & 0x0000ffff) != FLI_MAGIC) &&
  1492.         ((header.fhd_magic & 0x0000ffff) != FLC_MAGIC))
  1493.     {
  1494.         Printf ("'%s'", fileName);
  1495.         Quit (MPG_ERR);
  1496.     }
  1497.     /* Get the width and height */
  1498.  
  1499.     wwidth  = header.fhd_width;
  1500.     wheight = header.fhd_height;
  1501.  
  1502.     /* The speed is stored in 1/70 seconds, convert to usecs */
  1503.  
  1504.     if (fdelay < 0)
  1505.         fdelay = header.fhd_speed;
  1506.  
  1507.     convert_fdelay(); /* jiffies = 0; */
  1508.  
  1509. /*============================================================================*
  1510.  * timer stuff
  1511.  *============================================================================*/
  1512.  
  1513.     /* message port for communicating with timer device */
  1514.  
  1515.     if (!(TimerPort = CreateMsgPort()))
  1516.         Quit (TIM_ERR);
  1517.  
  1518.     /* our primary IO structure */
  1519.  
  1520.     if (!(TimerIO = (struct timerequest *)
  1521.       CreateIORequest (TimerPort, sizeof(struct timerequest))))
  1522.         Quit (TIM_ERR);
  1523.  
  1524.     if (timerclosed = OpenDevice (TIMERNAME, UNIT_MICROHZ,
  1525.                         (struct IORequest *) TimerIO, 0))
  1526.         Quit (TIM_ERR);
  1527.  
  1528.     TimerBase = (struct Library *) TimerIO->tr_node.io_Device;
  1529.  
  1530.     micros_per_eclock = 1000000.0 / (double)ReadEClock (&time0);
  1531.  
  1532. /*============================================================================*
  1533.  *  Initialisieren und Oeffnen des Displays.
  1534.  *============================================================================*/
  1535.  
  1536.     InitLibraries();
  1537.  
  1538.     /* Create a wwidth x wheight window to show the flick */
  1539.  
  1540.     InnerWidth  = wwidth;    /* Animationsgroesse (netto) merken */
  1541.     InnerHeight = wheight;
  1542.  
  1543.     FrameSize = wwidth * wheight;
  1544.  
  1545.     OpenMerlinPIP (wwidth, wheight);
  1546.  
  1547. /*============================================================================*/
  1548.  
  1549.     /* now allocate memory for the image */
  1550.  
  1551.     if (!(map = AllocVec (FrameSize, MEMF_CLEAR|MEMF_ANY)))
  1552.       Quit (MEM_ERR);
  1553.  
  1554.     data = map;
  1555.  
  1556.     /* Security Check */
  1557.  
  1558.     mem = AvailMem (MEMF_FAST);
  1559.  
  1560.     if ((header.fhd_frames*FrameSize) > (mem-(mem/4)))
  1561.       flag_noint = TRUE;
  1562.  
  1563.     ReadEClock (&time0);    /* read the start time */
  1564.  
  1565.     notfirst = FALSE;
  1566.     totalframes = 0;
  1567.  
  1568.     if (flag_noint)    /* Either interpret the file while displaying it */
  1569.     {
  1570.         if (repeatcount)
  1571.         {
  1572.             while (repeatcount--)
  1573.             {
  1574.                 interpret_fli (fd, &header, data, notfirst, func_disp);
  1575.                 notfirst = TRUE;
  1576.                 totalframes++;     
  1577.             }
  1578.         }
  1579.         else
  1580.         {
  1581.             for(;;)
  1582.             {
  1583.                 interpret_fli (fd, &header, data, notfirst, func_disp);
  1584.                 notfirst = TRUE;
  1585.                 totalframes++;     
  1586.             }
  1587.         }
  1588.     }
  1589.     else    /* Or interpret everything first and display it afterwards */
  1590.     {
  1591.         /* wait while loading the animation */
  1592.  
  1593.         /* Interpret it and store the results */
  1594.  
  1595.         disp_cur = &disp_root;
  1596.         interpret_fli (fd, &header, data, 0, func_interp);
  1597.  
  1598.         /* Now display the results */
  1599.  
  1600.         if (repeatcount)
  1601.         {
  1602.             while (repeatcount--)
  1603.             {
  1604.                 disp_cur = &disp_root;
  1605.  
  1606.                 while (disp_cur->disp_next)
  1607.                 {
  1608.                     disp_cur = disp_cur->disp_next;
  1609.  
  1610.                     /* Only display the first frame once */
  1611.  
  1612.                     if (disp_cur->disp_frame || !notfirst)
  1613.                       display_interp (disp_cur);
  1614.  
  1615.                     totalframes++;     
  1616.                 }
  1617.                 notfirst = TRUE;
  1618.             }
  1619.         }
  1620.         else
  1621.         {
  1622.             for (;;)
  1623.             {
  1624.                 disp_cur = &disp_root;
  1625.  
  1626.                 while (disp_cur->disp_next)
  1627.                 {
  1628.                     disp_cur = disp_cur->disp_next;
  1629.  
  1630.                     /* Only display the first frame once */
  1631.  
  1632.                     if (disp_cur->disp_frame || !notfirst)
  1633.                       display_interp (disp_cur);
  1634.  
  1635.                     totalframes++;     
  1636.                 }
  1637.                 notfirst = TRUE;
  1638.             }
  1639.         }
  1640.     }
  1641.     Quit (NO_ERR);
  1642. }
  1643.  
  1644.